7.3 defer

有这样一种场景,就是我们需要在函数执行结束之后进行一些操作。

比如我们通过代码打开了文件,那么我们需要保证在读取完文件以后,将文件进行关闭,这时候我们就会使用到defer

那么可能我们会有疑问,直接在读取完成以后直接关闭就可以了,为什么还要使用defer呢?

我们思考一种情况:当读取函数执行到一半的时候,发生panic导致了程序崩溃,这时候函数最后的关闭代码就肯定不会被执行了。

这种情况下,就可能会出现一些未知的问题。所以出现了defer,使用defer就可以保证文件关闭代码一定被执行,哪怕发生了panic,关闭代码同样会被执行。

本节代码存放目录为 lesson21

使用defer

上面我们了解到了defer的基本概念,接下来我们就尝试去使用看一下他的执行流程。代码如下所示:

func main() {
    deferPrint()
}

func deferPrint() {
    fmt.Printf("函数进入...\n")

    defer fmt.Println("函数结束,defer逻辑调用...")

    fmt.Printf("函数执行...\n")

    fmt.Printf("函数return...\n")

    return
}

执行上面的代码,结果输出如下:

函数进入...
函数执行...
函数return...
函数结束,defer逻辑调用...

从上面的代码中,我们可以看到defer是在最后调用的,这也就反映出了defer的特点。

下面我们演示panicdefer的执行情况。代码如下所示:

func deferPanic() {
    fmt.Printf("函数进入...\n")

    defer fmt.Println("函数结束,defer逻辑调用...")

    fmt.Printf("函数执行...\n")

    panic(errors.New("执行出错"))

    fmt.Printf("函数return...\n")

    return
}

指向上面的代码,结果输出如下所示:

函数进入...
函数执行...
函数结束,defer逻辑调用...
panic: 执行出错

goroutine 1 [running]:
main.deferPanic()
        /Users/xc/xcWork/YouCanGo/Code/YouCanGoCode/lesson21/lesson21.go:33 +0x151
main.main()
        /Users/xc/xcWork/YouCanGo/Code/YouCanGoCode/lesson21/lesson21.go:11 +0x2a
exit status 2

从上面的输出我们可以看出,函数执行以后发生了panic,这时候defer的代码仍然被调用了。

也就是说,当发生panic的时候,defer的逻辑同样是可以执行的,这有点类似于Javafinally

小结

本节我们介绍了defer,并且对defer进行了实际的测试。

关于本节总结如下:

  • defer在函数结束后调用

  • 发生panicdefer的逻辑仍然会执行

  • defer常用于在函数中关闭一些打开的资源,比如文件关闭

results matching ""

    No results matching ""